public class CasePacks {

   Entitlement__c e;
   
   //
   // Required sobject fields:
   //   - EntState__c
   //   - Cases_Remaining__c, Case_Pack__c, Renewal_Amount__c
   //   - Start_Date__c, End_Date__c
   //
   public CasePacks(Entitlement__c e) { this.e = e; }
   
   //
   // Testing helper methods
   //
   static Entitlement__c getEntSObject(Id entId) {
       return [select Id,EntState__c,Case_Pack__c,Cases_Remaining__c,Start_Date__c,End_Date__c,
           IsCasePackExhaustedYN__c,IsOutsideEffectivePeriodYN__c,IsBHInactiveYN__c, Business_Hours__c
           from Entitlement__c Where Id=:entId ];
   }
   static Support_Program__c mkNCSP() {
       Account a = new Account(Name='TEST-ACCT'); insert a;
       Support_Program__c sp = new Support_Program__c(Name='TEST-SP',
           Apply_To_All_Contacts_In_Account__c = true, RecordTypeId=RT.NCSPId, Account__c=a.Id );
       insert sp;
       return sp;
   }
   
   static Id mkEntWithCP(Integer numCasesRemaining,Integer numRenewal,Boolean TooEarly, Boolean TooLate) {
       Date dStart = (TooEarly) ? Date.today().addDays(10) : Date.today().addDays(-10); 
       Date dEnd = (TooLate) ? Date.today().addDays(-1) : Date.today().addDays(1);
        
       Entitlement__c eIns = new Entitlement__c(
           Cases_Remaining__c=numCasesRemaining, 
           Case_Pack__c=True, 
           Renewal_Amount__c=numRenewal,           
           Start_Date__c=dStart, 
           End_Date__c=dEnd ,
           Business_Hours__c=UT_SObjectFactory.DefBHId,
           Support_Program__c=mkNCSP().Id
       );
       insert eIns;
       
       return eIns.Id;
   }
   
   static Id mkEntWithoutCP(Boolean TooEarly, Boolean TooLate) {
       Date dStart = (TooEarly) ? Date.today().addDays(10) : Date.today().addDays(-10); 
       Date dEnd = (TooLate) ? Date.today().addDays(-1) : Date.today().addDays(1);
        
       Entitlement__c eIns = new Entitlement__c(
           Case_Pack__c=False, 
           Start_Date__c=dStart, 
           End_Date__c=dEnd,
           Business_Hours__c=UT_SObjectFactory.DefBHId ,
           Support_Program__c=mkNCSP().Id
       );
       insert eIns;
       return eIns.Id;
   }
    
   //
   // Test Methods
   //  
   static testMethod void testActive() {
       Entitlement__c eTest = [select 
           Id,EntState__c,Case_Pack__c,Start_Date__c,End_Date__c
           //,IsCasePackExhaustedYN__c,IsOutsideEffectivePeriodYN__c, IsBHInactiveYN__c, Business_Hours__r.Id
           from Entitlement__c Where Id=:mkEntWithoutCP(false,false) ];
       //System.debug('>>>>'+eTest);
       CasePacks cp = new CasePacks( eTest );
       System.assertEquals(True,cp.IsActive(),'Expected Active');
   }
   
   static testMethod void testInactive() {
       Entitlement__c eTest1 = [select Id,EntState__c,Case_Pack__c,Start_Date__c,End_Date__c
           //,IsCasePackExhaustedYN__c,IsOutsideEffectivePeriodYN__c,IsBHInactiveYN__c, Business_Hours__c
           from Entitlement__c Where Id=:mkEntWithoutCP(true,false) ];
       Entitlement__c eTest2 = [select Id,EntState__c,Case_Pack__c,Start_Date__c,End_Date__c 
           //,IsCasePackExhaustedYN__c,IsOutsideEffectivePeriodYN__c,IsBHInactiveYN__c, Business_Hours__c
           from Entitlement__c Where Id=:mkEntWithoutCP(false,true) ];           
       CasePacks cp1 = new CasePacks( eTest1 );
       CasePacks cp2 = new CasePacks( eTest2 );       
       System.assertEquals(False,cp1.IsActive(),'Expected Inactive b/c too early');
       System.assertEquals(False,cp2.IsActive(),'Expected Inactive b/c passed end date');
   }   

   static testMethod void testDecrementAndIncrement() {
       Entitlement__c eTest1 = getEntSObject( mkEntWithCP(1,0,false,false) );
       Entitlement__c eTest2 = getEntSObject( mkEntWithCP(0,0,false,false) ); 
       System.debug( 'eTest1.Cases_Remaining__c='+eTest1.Cases_Remaining__c );
       System.debug( 'eTest2.Cases_Remaining__c='+eTest2.Cases_Remaining__c );          
       CasePacks cp1 = new CasePacks( eTest1 );
       CasePacks cp2 = new CasePacks( eTest2 );       
       System.assertEquals(True,cp1.IsActive(),'Expected active');
       System.assertEquals(false,cp2.IsActive(),'Expected inactive b/c no cases');
       cp1.Decrement();
       cp2.Increment();
       update eTest1;
       update eTest2;

       eTest1 = getEntSObject(eTest1.Id);
       eTest2 = getEntSObject(eTest2.Id);
       System.debug( '** eTest1='+eTest1 );
       System.debug( '** eTest2='+eTest2 );
       cp1 = new CasePacks( eTest1 );
       cp2 = new CasePacks( eTest2 );              
       System.debug( 'eTest1.Cases_Remaining__c='+eTest1.Cases_Remaining__c );
       System.debug( 'eTest2.Cases_Remaining__c='+eTest2.Cases_Remaining__c );
       System.assertEquals(False,cp1.IsActive(),'Expected inactive b/c 0 cases');
       System.assertEquals(True,cp2.IsActive(),'Expected active b/c added 1 case');
       System.assertEquals(0,eTest1.Cases_Remaining__c,'Expected decrement to reduce');
       System.assertEquals(1,eTest2.Cases_Remaining__c,'Expected increment to increase');       
   }      

   static testMethod void testDecrementAndIncrementOnNonCPEnts() {
       Entitlement__c eTest = getEntSObject( mkEntWithoutCP(false,false) );
       System.assertEquals( null,eTest.Cases_Remaining__c,'Non-CP Ents must have null in this field' );          
       CasePacks cp = new CasePacks( eTest );
       System.assertEquals(True,cp.IsActive(),'Expected active');
       cp.Decrement();
       cp.Increment();
       update eTest;

       eTest = getEntSObject(eTest.Id);
       System.debug( '** eTest='+eTest );
       cp = new CasePacks( eTest );
       System.assertEquals( null,eTest.Cases_Remaining__c,'Non-CP Ents must have null in this field' );          
       System.assertEquals(True,cp.IsActive(),'Expected still active');
   }      
   
   //
   // Implementation methods
   //
   public Boolean IsActive() {
       // Preconditions
       System.assertNotEquals(e,null,'e must be non-null');
       System.assertNotEquals(e.EntState__c,null,'e.EntState__c must be non-null');       
       
       return e.EntState__c.contains('Active');
   }
   
   private void AddToCasesRemaining(Integer howMany) {
       // Preconditions
       System.assertNotEquals(e,null,'e must be non-null');

       if (this.e.Case_Pack__c==True) {            
           this.e.Cases_Remaining__c += howMany; 
       }
   }
   
   public void Increment() {
       AddToCasesRemaining(1);
   }
   
   public void Decrement() {
       AddToCasesRemaining(-1);
   }

}